package cn.com.hatech.blog.module.admin.article.service.impl;

import cn.com.hatech.blog.common.constant.LogActions;
import cn.com.hatech.blog.common.constant.Types;
import cn.com.hatech.blog.common.constant.WebConst;
import cn.com.hatech.blog.common.exception.TipException;
import cn.com.hatech.blog.common.utils.UserRequest;
import cn.com.hatech.blog.module.admin.article.entity.Article;
import cn.com.hatech.blog.module.admin.article.entity.ArticleMeta;
import cn.com.hatech.blog.module.admin.article.mapper.ArticleMapper;
import cn.com.hatech.blog.module.admin.article.mapper.ArticleMetaMapper;
import cn.com.hatech.blog.module.admin.article.service.IArticleService;
import cn.com.hatech.blog.module.admin.category.service.IMetaService;
import cn.com.hatech.blog.module.admin.dashboard.service.ILogService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @projectName: hatech-blog
 * @package: cn.com.hatech.blog.module.admin.service.impl
 * @className: ContentServiceImpl
 * @author: xuruikai
 * @description: 文章内容业务层接口实现
 * @date: 2020/1/11 14:27
 * @version: 1.0
 */
@Slf4j
@Service("contentsService")
public class ArticleServiceImpl extends ServiceImpl< ArticleMapper,  Article> implements IArticleService {

    @Resource
    private ArticleMapper contentMapper;

    @Resource
    private IMetaService metaService;

    @Resource
    private ArticleMetaMapper contentMetaMapper;
    /**
     * 日志业务层接口注入
     */
    @Autowired
    private ILogService logService;

    @Override
    public IPage<Article> selectPublishContentPage(Integer page, Integer limit) {
        QueryWrapper<Article> contentQueryWrapper = new QueryWrapper<>();
        contentQueryWrapper.lambda().eq(Article::getStatus, 1);
        // 创建时间倒序
        return getContentPage(page, limit, contentQueryWrapper);
    }

    @Override
    public IPage<Article> getArticles(String metaId, int page, int limit) {
        QueryWrapper<ArticleMeta> contentMetaQueryWrapper = new QueryWrapper<>();
        contentMetaQueryWrapper.lambda().eq(ArticleMeta::getMetaId, metaId);
        List<ArticleMeta> contentMetas = this.contentMetaMapper.selectList(contentMetaQueryWrapper);
        // 关联文章id集合
        List<String> articleIds = contentMetas.stream().map(ArticleMeta::getArticleId).collect(Collectors.toList());
        QueryWrapper<Article> contentQueryWrapper = new QueryWrapper<>();
        // TODO 枚举枚举
        contentQueryWrapper.lambda()
                .in(Article::getId, articleIds)
                .eq(Article::getStatus, 1);
        // 创建时间倒序
        return getContentPage(page, limit, contentQueryWrapper);
    }

    @Override
    public IPage<Article> getArticlesByKeyword(String keyword, int page, int limit) {
        QueryWrapper<Article> contentQueryWrapper = new QueryWrapper<>();
        contentQueryWrapper.lambda().eq(Article::getStatus, 1);
        contentQueryWrapper.and(likeQueryWrapper -> likeQueryWrapper
                .lambda()
                .like(Article::getTitle, keyword)
                .or()
                .like(Article::getContent, keyword));
        // 创建时间倒序
        return getContentPage(page, limit, contentQueryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int publish(Article content) {
        // 设置创建人id
        content.setAuthorId(UserRequest.getCurrentUserId());
        content.setCreateTime(new Date());
        content.setUpdateTime(new Date());
        // 入参校验
        this.checkContentForm(content);
        if (StringUtils.isEmpty(content.getCategories())) {
            content.setCategories("默认分类");
        }
        contentMapper.insert(content);
        // 处理文章关联的分类(category和tag)数据
        return this.handleContentMetaData(content);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateArticle(Article content) {
        // 设置创建人id
        content.setAuthorId(UserRequest.getCurrentUserId());
        content.setContent(content.getContent());
        content.setUpdateTime(new Date());
        // 入参校验
        this.checkContentForm(content);
        // 处理文章关联的分类(category和tag)数据
        this.handleContentMetaData(content);
        return contentMapper.updateById(content);
    }

    @Override
    public Article selectById(String id) {
        if (StringUtils.isEmpty(id)) {
            return null;
        }
        // 处理关联分类数据
        Article content = this.handleContentMetaQueryData(contentMapper.selectById(id));
        if (content != null) {
            log.info("浏览次数: {}", content.getHits());
            // 浏览次数+1
            content.setHits(content.getHits() + 1);
            contentMapper.updateById(content);
        }
        return content;
    }

    @Override
    public Article selectByIdWithoutHit(String id) {
        if (StringUtils.isEmpty(id)) {
            return null;
        }
        // 处理关联分类数据
        return this.handleContentMetaQueryData(contentMapper.selectById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteById(String id) {
        if (null == this.selectById(id)) {
            throw new TipException("文章不存在,删除失败");
        }
        logService.insertLog(LogActions.DEL_ARTICLE.getAction(), id, UserRequest.getRemoteAddr(), UserRequest.getCurrentUserId());
        return contentMapper.deleteById(id);
    }


    /**
     * 校验发布/编辑时文章相关字段
     *
     * @param content
     */
    private void checkContentForm(Article content) {
        if (null == content) {
            throw new TipException("文章对象为空");
        }
        if (StringUtils.isEmpty(content.getTitle())) {
            throw new TipException("文章标题不能为空");
        }
        if (StringUtils.isEmpty(content.getContent())) {
            throw new TipException("文章内容不能为空");
        }
        int titleLength = content.getTitle().length();
        if (titleLength > WebConst.MAX_TITLE_COUNT) {
            throw new TipException("文章标题过长");
        }
        int contentLength = content.getContent().length();
        if (contentLength > WebConst.MAX_TEXT_COUNT) {
            throw new TipException("文章内容过长");
        }
        if (null == content.getAuthorId()) {
            throw new TipException("请登录后发布文章");
        }
    }

    /**
     * 处理文章关联的分类数据(category和tag)
     *
     * @param content
     */
    private int handleContentMetaData(Article content) {
        return this.metaService.saveMetas(content.getId(), content.getCategories(), content.getTags());
    }


    /**
     * 获取文章信息分页列表
     *
     * @param page
     * @param limit
     * @param contentQueryWrapper
     * @return
     */
    private IPage<Article> getContentPage(int page, int limit, QueryWrapper<Article> contentQueryWrapper) {
        contentQueryWrapper.orderByDesc("create_time");
        IPage<Article> contentPage = contentMapper.selectPage(new Page<>(page, limit), contentQueryWrapper);
        return contentPage.setRecords(this.handleContentMetaQueryDataList(contentPage.getRecords()));
    }

    /**
     * 处理查询结果
     *
     * @param contents
     * @return
     */
    private List<Article> handleContentMetaQueryDataList(List<Article> contents) {
        return contents.stream()
                // 处理关联数据
                .map(content -> this.handleContentMetaQueryData(content))
                .collect(Collectors.toList());
    }

    /**
     * 处理查询文章时关联的分类数据(category和tag)
     *
     * @param content
     */
    private Article handleContentMetaQueryData(Article content) {
        // 分类
        content.setCategories(metaService.getMetaNamesByMetaIds(getMetaIdsByContentId(content.getId()), Types.CATEGORY.getType()));
        // 标签
        content.setTags(metaService.getMetaNamesByMetaIds(getMetaIdsByContentId(content.getId()), Types.TAG.getType()));
        return content;
    }

    private List<String> getMetaIdsByContentId(String contentId) {
        QueryWrapper<ArticleMeta> contentMetaQueryWrapper = new QueryWrapper<>();
        contentMetaQueryWrapper.lambda().eq(ArticleMeta::getArticleId, contentId);
        // 判断是否存在分类或者标签
        return contentMetaMapper.selectList(contentMetaQueryWrapper)
                .stream()
                .map(ArticleMeta::getMetaId)
                .collect(Collectors.toList());
    }

}